﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Collections;
using System.Collections.ObjectModel;

namespace FAST
{
    public class Main
    {
        private UpdateDetection ud;
        private UpdateReconcilation ur;
        private FolderPairHandler fpHandler;
        private string storagePath;
        private Serializer ser;
        private List<ConflictsObject> conflictList;


        public Main() //exclude ui item
        {
            storagePath = Application.StartupPath + @"\sessions.dat";
            ser = new Serializer();

            initializeFolderPairs();

            conflictList = new List<ConflictsObject>();
            ud = new UpdateDetection(fpHandler);
            ur = new UpdateReconcilation();
        }

       /* public ArrayList populateConflictList()
        {
            //ConflictsCore core = new ConflictsCore(leftListDetails, rightListDetails, left_ConflictList, right_ConflictList);
            //ArrayList conflictList = core.createConflictList();
            //return conflictList;
        }*/

        private void initializeFolderPairs()//refactor
        {
            if (File.Exists(storagePath))
                fpHandler = ser.deserializeFolderPairHandler(storagePath);
            else
            {
                fpHandler = new FolderPairHandler();
            }
        }

        private void storeFolderPairs()
        {
            ser.serializeFolderPairHandler(storagePath, this.fpHandler);
        }

        public void previewWithoutOS(string src, string des)//method use with balancing listview
        {
            ud.removeOS();
            ud.processLeftFolder(src);
            ud.processRightFolder(des);
        }


        /***************************************************** FP Methods ********************************************/
        //Method name : twoWaySync() : MessageLog
        //Parameters  : src(type string), des(type string)
        //Description :  Retrieve left/right list of FilesHandler object, process the status, create folder pair if it does not exist and sync data across drive. 
        //Exceptions  :  IndexOutOfRangeException: Shifting position of list may incur this exception, FileNotFoundException: Invalid source or destination file path, DirectoryNotFoundException: Invalid source or destination directory path, UnauthorizedAccessException: Copy Read-only file to destination.
        public MessageLog twoWaySync(string src, string des, string fpName, bool isFirstSync)
        {
            try
            {
                ud.processLeftFolder(src);
                ud.processRightFolder(des);

                List<FilesHandler> leftList = ud.getLeftFolderList();
                List<FilesHandler> rightList = ud.getRightFolderList();

                ur.performReconcilation(leftList, rightList, src, des);

                /** Check conflict here and initialize and load ur UI conflict form**/
                List<int[]> leftConList = ur.getLeftConList();
                List<int[]> rightConList = ur.getRightConList();

                if (leftConList.Count != 0 && rightConList.Count != 0)
                {
                    /**new ur conflict form here => take is leftRightList
                    * e.g. Conflicts con = new Conflicts(leftList, rightList, this.leftConList, 				this.rightConList);
                        con.ShowDialog();
                    **/
                    ConflictsCore core = new ConflictsCore(leftList, rightList, leftConList, rightConList);
                    conflictList = core.createConflictList();



                    ur.performReconcilation(leftList, rightList, src, des);
                }
                //assume both left and right list same unless LModRDelete/RModLDelete conflict
                
                //if (sess.getSessionsCount() == 0)
                if (isFirstSync)
                    fpHandler.createNewFolderPair(fpName);

                fpHandler.updateFolderPair(src, des, leftList, rightList);//update os and versioning of current folder pair, ie latest added folder pair
                storeFolderPairs();

                //check if system data exist in another drive and sync if necessary.
                //syncData(src, des);
                //syncData(des, src);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
            return ur.generateMsgLog();

        }
        /*
        public List<int[]> stageOne(string src, string des, string fpName, bool isFirstSync)
        {
            ud.processLeftFolder(src);
            ud.processRightFolder(des);

            List<FilesHandler> leftList = ud.getLeftFolderList();
            List<FilesHandler> rightList = ud.getRightFolderList();

            ur.performReconcilation(leftList, rightList, src, des);

            return ur.getLeftConList();
        }

        public void stageTwo(List<int[]> leftConList)
        {
            List<int[]> rightConList = ur.getRightConList();
        }
        */

        public List<ConflictsObject> getConflictList()
        {
            return this.conflictList;
        }

        public bool isFolderPairNameUnique(string fpName)
        {
            return fpHandler.isFolderPairNameUnique(fpName);
        }

        public void initializeNewFolderPair()
        {
            fpHandler.resetLoadedFolderPair();
            storeFolderPairs();
        }

        public void loadFolderPairByName(string name)
        {
            fpHandler.loadFolderPairByName(name);
            storeFolderPairs();
        }

        public void removeFolderPairByName(string keyName)
        {
            fpHandler.removeLastLoadedFolderPair(keyName);
            storeFolderPairs();
        }

        public string getFolderPairLog()
        {
            return fpHandler.getLastLoadedFolderPairLog();
        }

        public string getFolderPairName()
        {
            return fpHandler.getLastLoadedFolderPairName();
        }

        public Dictionary<string, FolderPairItem> retrieveFolderPairs()
        {
            return fpHandler.getFolderPairs();
        }

        public string getFPLeftFolderPath()
        {
            return fpHandler.getFolderPairLeftFolderPath();
        }

        public string getFPRightFolderPath()
        {
            return fpHandler.getFolderPairRightFolderPath();
        }
        
        /*********************************************************************************************************************/
        public void syncData(string src, string des)
        {
            // Display src drive information.
            DriveInfo srcDrive = new DriveInfo(src);
            // Display des drive information.
            DriveInfo desDrive = new DriveInfo(des);
            try
            {
                if (!srcDrive.Name.Equals(desDrive.Name))
                {
                    DirectoryInfo sourcedinfo = new DirectoryInfo(Application.StartupPath);
                    DirectoryInfo destinfo = new DirectoryInfo(Path.Combine(desDrive.Name, @"Sessions"));

                    DirectoryInfo di = new DirectoryInfo(Application.StartupPath + @"\Sessions");
                    //DirectoryInfo desDi = new DirectoryInfo(destinfo.ToString() + @"\Session");
                    //Hide and Disallow user to access the storage file.
                    copyAllFiles(di, destinfo);
                    File.Copy(Application.StartupPath + @"\session.dat", desDrive.Name + @"\session.dat", true);
                    File.SetAttributes(Path.Combine(desDrive.Name, @"Sessions"), FileAttributes.ReadOnly | FileAttributes.Hidden);

                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        public void copyAllFiles(DirectoryInfo source, DirectoryInfo target)
        {
            try
            {
                // Check if the target directory exists, if not, create it.
                if (Directory.Exists(target.FullName) == false)
                {
                    Directory.CreateDirectory(target.FullName);
                }

                // Copy each file into it’s new directory.
                foreach (FileInfo fi in source.GetFiles())
                {
                    Console.WriteLine(@"Copying {0}\{1}", target.FullName, fi.Name);
                    fi.CopyTo(Path.Combine(target.ToString(), fi.Name), true);
                }

                // Copy each subdirectory using recursion.
                foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
                {
                    DirectoryInfo nextTargetSubDir = target.CreateSubdirectory(diSourceSubDir.Name);
                    copyAllFiles(diSourceSubDir, nextTargetSubDir);
                }
            }
            catch (Exception)
            {
            }
        }

        //versioning
        public List<FileVersioningList> getFVList()
        {
            FileVersioning fv = new FileVersioning();
            return fv.getListOfFVList();
        }
        public List<FileHandler> getVersionList(int index)
        {
            List<FileVersioningList> fileVersionList;
            List<FileHandler> FVList;
            FileVersioning fv = new FileVersioning();
            fileVersionList = fv.getListOfFVList();
            FVList = fv.getListOfFVList()[index].getListOfFH();
            return FVList;
        }
        public void setVersionList(List<FileHandler> vList, int idx)
        {
            FileVersioning fv = new FileVersioning();
            fv.setVersionListByIdx(vList, idx);
        }

        /************NEW FOR UI REVERT**************/
        public void revertVersion(string path, int versionIdx, int verNumber)
        {
            FileHandler fh = new FileHandler(path, ""); //Note: subFilePath set to empty!
            fh.setVersioningIdx(versionIdx);
            FileVersioning fv = new FileVersioning();
            fv.revertVersion(fh, verNumber);
            
        }

        public bool isCurrentRevertedVersion(int verIdx,int idx)
        {
            FileVersioning fv = new FileVersioning();
            return fv.getListOfFVList()[verIdx].getCurrentRevertedVersion() == idx;
        }
        /*******************************************/

        public List<FilesHandler> generateLeftList()
        {
            return ud.getLeftFolderList();
        }
        public List<FilesHandler> generateRightList()
        {
            return ud.getRightFolderList();
        }

        private List<FilesHandler> leftListDetails = new List<FilesHandler>();
        private List<FilesHandler> rightListDetails = new List<FilesHandler>();

        public List<FilesHandler> RightListDetails
        {
            get { return rightListDetails; }
            set { rightListDetails = value; }
        }
        public List<FilesHandler> LeftListDetails
        {
            get { return leftListDetails; }
            set { leftListDetails = value; }
        }
           
    }
}
